"""
Copyright 2009, Thomas Dejanovic.

This is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.

This software is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this software; if not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
02110-1301 USA, or see the FSF site: http://www.fsf.org.
"""
#---------------------------------------------------------------------

id = "$Id: verilog_bus.py 672 2010-07-07 05:42:13Z rabidfruitbat $"
# $URL: http://hatch.googlecode.com/svn/tags/taggle_release_3.0/hatch/hatch_targets/verilog/verilog_bus.py $
# $Author: rabidfruitbat $
version = " ".join(id.split()[1:3])

#---------------------------------------------------------------------

import re
import math

#---------------------------------------------------------------------

class TargetBus(object):

    def __init__ (self, hatchNode, parent):

        # set sane default values.
        self.name      = ""
        self.function  = ""
        self.addressWidth = 30
        self.dataWidth    = 32
        self.parent = parent
        self.ports  = parent.ports
        self.nets   = parent.nets

        try:
            self.prefix = hatchNode.properties['prefix']
        except KeyError, e:
            self.prefix = ""

        # figure out how much stuff we have to address - this is an
        # over simplification of the calculation.  you should be able
        # to look at the address and figure out which bits are need to
        # uniquily address al lthe registers in the local scope and
        # use the rest of the address to generate a block select.
        # TODO - what I said above - thomasd

        # addrRange is the number of locations use din this module.
        # indexing off base address is abit of a hack.
        addrRange  = hatchNode.properties['address_range'] + hatchNode.properties['base_address']
        decodeBits = int(math.ceil(math.log(addrRange) / math.log(2)))

        print "decodeBits = %d, addrRange = %d"%(decodeBits, addrRange)

        targetProperty = hatchNode.properties.get('target', '') # Get empty string if 'target' proeprty does not exist.

        if re.match("^.*\s+apb\s*.*$", targetProperty):
            self.name = 'apb'
            try:
                value = hatchNode.properties['address_width']
            except KeyError, e:
                self.addressWidth = 30
            else:
                self.addressWidth = value

            # Not mutually exclusive:
            if re.match("^\s*(?P<size>.*)\s*apb\s+slave\s+mux\s*$", targetProperty) :
                self.function = 'mux'
                raise NotImplementedError, "Specified bus target %s is not implemented." % (targetProperty)
            elif re.match("^\s*(?P<size>.*)\s*apb\s+slave\s*$", targetProperty) :
                self.function = 'slave'
                self.buildApbSlave()
            else :
                raise NotImplementedError, "Specified APB target %s is not implemented." % (targetProperty)


        elif re.match("^(.*\s+|)lpcb\s+.*$", targetProperty): # low pin count bus.
            self.name = 'lpcb'


            # try:
            #     value = hatchNode.properties['address_width']
            # except KeyError, e:
            #     hatchNode.properties['address_width'] = 16
            #     self.addressWidth = 16
            # else:
            #     self.addressWidth = value

            # there is a BUG!  use of address_width is inconsistent
            # and switches between address bits, range and a bunch of
            # other things.  need to fix this!
            # TODO - what I said above - thomasd

            #
            # this breaks the decode into two steps.  the first step
            # is to decode the address in 4 bit nibles as it comes in.
            # at the moment we just assert that they are all 0, and
            # the active part of the decode is in the remaining bits.
            # this is a bit of a cop out, but works for now.
            # TODO - improve this - thomasd
            if decodeBits <= 4 :
                hatchNode.properties['address_width'] = 4
                self.addressWidth = 4
                decodeBits = 4
            elif decodeBits <= 8 :
                hatchNode.properties['address_width'] = 8
                self.addressWidth = 8
                decodeBits = 8
            elif decodeBits <= 12 :
                hatchNode.properties['address_width'] = 12
                self.addressWidth = 12
                decodeBits = 12
            elif decodeBits <= 16 :
                hatchNode.properties['address_width'] = 16
                self.addressWidth = 16
                decodeBits = 16
            elif decodeBits <= 20 :
                hatchNode.properties['address_width'] = 20
                self.addressWidth = 20
                decodeBits = 20
            elif decodeBits <= 24 :
                hatchNode.properties['address_width'] = 24
                self.addressWidth = 24
                decodeBits = 24
            else:
                raise "You have got to be kidding!, you seriousely have that many things to address."


            if re.match("^(.*\s+|)lpcb\s+slave\s*$", targetProperty) :
                self.function = 'slave'
                self.buildLpcbSlave()
            else:
                print "LPCB MUX! - the verilog file will be empty, DON'T PANIC!"
                self.function = 'mux'
                # don't do anything for the verilog here now.


        elif re.match("^.*\s+ubus\s+.*$", targetProperty): # micro bus between FPGA's.
            self.name = 'ubus'

            try:
                value = hatchNode.properties['address_width']
            except KeyError, e:
                self.addressWidth = 16
            else:
                self.addressWidth = value


            if re.match("^\s*(?P<size>.*)\s*ubus\s+slave\s+mux\s*$", targetProperty) :
                self.function = 'mux'
                raise NotImplementedError, "Specified uBus target %s is not implemented." % (targetProperty)
            elif re.match("^\s*(?P<size>.*)\s*ubus\s+slave\s*$", targetProperty) :
                self.function = 'slave'
                self.buildUbusSlave()
            elif re.match("^\s*(?P<size>.*)\s*ubus\s+bridge\s*$", targetProperty) :
                self.function = 'bridge'
                raise NotImplementedError, "Specified uBus target %s is not implemented." % (targetProperty)
            else:
                raise NotImplementedError, "Specified uBus target %s is not implemented." % (targetProperty)
        else:
            print "\nWARNING!!  " + "Specified bus target %s is not implemented." % (targetProperty)
            raw_input("Hit enter to continue anyway.\n\n")


        self.addrWidthString  = "[%d:0]"%(self.addressWidth-1)
        self.dataWidthString  = "[%d:0]"%(self.dataWidth-1)

        self.localAddressWidth    = decodeBits
        self.localAddrWidthString = "[%d:0]"%(decodeBits-1)


    def buildApbSlave(self):
        """
        """

        prefix = self.prefix

        self.parent.verilogSetup = "  //- - - - - - - - - - -  setup the apb slave. - - - - - - - - - - - - - - -\n"
        # clocks and reset.
        self.clk        = "%spclk"%(prefix)
        self.clkEn      = "%spclk_en"%(prefix)
        self.gatedClk   = "%sgated_pclk"%(prefix)
        self.gatedClkEn = "%sgated_pclk_en"%(prefix)

        self.ports.add(self.clk, 'input_port', 1)
        self.ports.add(self.clkEn, 'input_port', 1)
        self.ports.add(self.gatedClk, 'input_port', 1)
        self.ports.add(self.gatedClkEn, 'input_port', 1)

        # change reset to be active high because [ soap box monologue deleted ].
        self.reset      = "preset"

        self.ports.add("%spreset_l"%(prefix), 'input_port', 1)
        self.nets.add(self.reset, 'wire', 1)
        self.parent.verilogSetup += """
  // make an active high reset.
  assign preset  = ~%spreset_l;
"""%(prefix)

        self.addr       = "%spaddr"%(prefix)
        self.writeData  = "%spwdata"%(prefix)
        self.writeEn    = "%spwrite"%(prefix)
        self.readData   = "%sprdata"%(prefix)
        self.readEn     = ""

        self.ports.add("%spenable"%(prefix), 'input_port', 1)
        self.ports.add("%spsel"%(prefix),    'input_port', 1)
        self.ports.add(self.addr,      'input_port', 30) # xxxxx this is a bug, it should be self.addressWidth
        self.ports.add(self.writeData, 'input_port', self.dataWidth)
        self.ports.add(self.writeEn,   'input_port', 1)
        self.ports.add(self.readData,  'output_port', self.dataWidth)

        # pipeline address decode, so change the signals used.
        self.writeEn    = "pwrite_en"
        self.readData   = "prdata_int"
        self.readEn     = "pread_en"

        self.nets.add(self.writeEn,    'wire', 1)
        self.nets.add(self.readData,   'reg', self.dataWidth)
        self.nets.add(self.readEn,     'wire', 1)
        self.nets.add("pread_en_int",  'reg', 1)
        self.nets.add("pwrite_en_int", 'reg', 1)

        self.parent.verilogSetup += """            
  //
  // psel will be a combinatorial decode of the upper address bits so
  // we should register it here to make the timing a little easier and
  // remove a multicycle path (apb is a 2 cycle access with address
  // set up in the first cycle). No need to make the physical design
  // harder than it needs to be  :-)
  //
  always @ (posedge %s) if (%s) begin
    if (%s) begin
"""%(self.gatedClk, self.gatedClkEn, self.reset)

        self.parent.verilogSetup += """
      pread_en_int  <= 1'd0;
      pwrite_en_int <= 1'd0;
    end else begin
      pread_en_int  <= %spsel & ~%spwrite;
      pwrite_en_int <= %spsel &  %spwrite;
    end
  end
"""%(prefix, prefix, prefix, prefix)
        
        self.parent.verilogSetup += """
  assign pread_en  = %spenable & pread_en_int;
  assign pwrite_en = %spenable & pwrite_en_int;
  assign %sprdata  = pread_en ? %s : 32'd0;
"""%(prefix, prefix, prefix, self.readData)

        # tail the verilogSetup string.
        self.parent.verilogSetup += """

  //- - - - - - - - - - - end of apb slave setup. - - - - - - - - - - -
"""
    # end of buildApbSlave()



    def buildLpcbSlave(self):
        """
        """

        prefix = self.prefix

        self.parent.verilogSetup = """
  //- - - - - - - - - - -  setup the lpcb slave. - - - - - - - - - - - - - - -

`include "lpcb_defines.vh"

"""
        # clocks and reset.
        self.ports.add("%sclk"%(prefix), 'input_port', 1)
        self.ports.add("%sclk_en"%(prefix), 'input_port', 1)
        self.ports.add("%sgated_clk"%(prefix), 'input_port', 1)
        self.ports.add("%sgated_clk_en"%(prefix), 'input_port', 1)
        self.ports.add("%sreset"%(prefix), 'input_port', 1)

        # the basic interface.
        self.ports.add("%slpcb_frame_in"%(prefix), 'input_port', 1);
        self.ports.add("%slpcb_cad_in"%(prefix), 'input_port', 4);
        self.ports.add("%slpcb_frame_out"%(prefix), 'output_port', 1);
        self.ports.add("%slpcb_cad_out"%(prefix), 'output_port', 4);


        self.clk        = "clk"
        self.clkEn      = "clk_en"
        self.gatedClk   = "gated_clk"
        self.gatedClkEn = "gated_clk_en"
        self.reset      = "reset"

        self.addr       = "addr"
        self.writeData  = "writeData"
        self.writeEn    = "writeEn"
        self.readData   = "readData"
        self.readEn     = "readEn"

        self.nets.add("addr",         'reg', self.addressWidth);
        self.nets.add("writeData",    'reg', self.dataWidth);
        self.nets.add("writeEn",      'reg', 1);
        self.nets.add("readData",     'reg', self.dataWidth);
        self.nets.add("readData_int", 'reg', self.dataWidth);
        self.nets.add("readEn",       'reg', 1);

        if (prefix != ""):
            self.nets.add('clk',          'wire', 1)
            self.nets.add('clk_en',       'wire', 1)
            self.nets.add('gated_clk',    'wire', 1)
            self.nets.add('gated_clk_en', 'wire', 1)

            self.parent.verilogSetup += """
  /*------------------------------------------------------------------
   *
   * connect the prefixed clock and interface signals to our generic
   * internal signal names to keep the template code simple.
   *
   * */

  assign clk = %sclk;
  assign clk_en = %sclk_en;
  assign gated_clk = %sgated_clk;
  assign gated_clk_en = %sgated_clk_en;
  assign reset = %sreset;

"""%(prefix, prefix, prefix, prefix, prefix)

        self.nets.add("frame_in",  'wire', 1);
        self.nets.add("cad_in",    'wire', 4);
        self.nets.add("frame_out", 'reg',  1);
        self.nets.add("cad_out",   'reg',  4);

        self.nets.add("frame_int",  'reg', 1);
        self.nets.add("cad_int",    'reg', 4);

        self.nets.add("lpcb_state", 'reg', 3);
        self.nets.add("lpcb_count", 'reg', 5);
        self.nets.add("lpcb_cmd",   'reg', 4);
        self.nets.add("lpcb_sel",   'reg', 1);

        self.parent.verilogSetup += """
  /*------------------------------------------------------------------
   *
   * connect the generic bus interface signals to the named ports.
   *
   * */

  assign frame_in = %slpcb_frame_in;
  assign cad_in = %slpcb_cad_in;
  assign %slpcb_frame_out = frame_out;
  assign %slpcb_cad_out   = cad_out;

"""%(prefix, prefix, prefix, prefix)

        self.parent.verilogSetup += """            
  /*------------------------------------------------------------------
   *
   * simple FSM to run the lpcb.
   *
   * */

  always @ (posedge clk) if (clk_en) begin
    if (reset) begin
      frame_int <= 1'd0;
      cad_int   <= 4'd0;
    end else begin
      frame_int <= frame_in;
      cad_int   <= cad_in;
    end
  end


  parameter LPCB_ADDRESS_WIDTH = %2d;
  parameter LPCB_DATA_WIDTH    = %2d;
"""%(self.addressWidth, self.dataWidth)

        self.parent.verilogSetup += """            
  parameter [2:0] // synopsys enum lpcb_state
               RX_IDLE           = 3'd0,

               PASS_THROUGH      = 3'd1,
               GET_ADDR          = 3'd2,
               GET_WRITE_DATA    = 3'd3,
               GET_READ_DATA     = 3'd4,
               SEND_COMMAND      = 3'd5,
               SEND_READ_DATA    = 3'd6,

               END               = 3'd7;


  // reg [4:0] /* synopsys enum lpcb_state */ lpcb_state;

`ifdef IVERILOG
  /*-AUTOASCIIENUM("lpcb_state", "ascii_lpcb_state", nul)*/
  // Beginning of automatic ASCII enum decoding
  reg [111:0]             ascii_lpcb_state;       // Decode of lpcb_state
  always @(lpcb_state) begin
    case ({lpcb_state})
      RX_IDLE:        ascii_lpcb_state = "rx_idle       ";
      PASS_THROUGH:   ascii_lpcb_state = "pass_through  ";
      GET_ADDR:       ascii_lpcb_state = "get_addr      ";
      GET_WRITE_DATA: ascii_lpcb_state = "get_write_data";
      GET_READ_DATA:  ascii_lpcb_state = "get_read_data ";
      SEND_COMMAND:   ascii_lpcb_state = "send_command  ";
      SEND_READ_DATA: ascii_lpcb_state = "send_read_data";
      END:            ascii_lpcb_state = "end           ";
      default:        ascii_lpcb_state = "%Error        ";
    endcase
  end
  // End of automatics
`endif

  wire lpcb_abort;
  assign lpcb_abort = frame_int && ((cad_int == `LPCB_RESET_CMD) || (cad_int == `LPCB_ABORT_CMD));

  always @ (posedge clk) if (clk_en) begin
    if (reset) begin
      lpcb_state <= RX_IDLE;
      lpcb_count <= 5'd0;
      lpcb_cmd   <= 4'd0;
      lpcb_sel   <= 1'd0;
      addr       <= {LPCB_ADDRESS_WIDTH {1'd0}};
      writeData    <= {LPCB_DATA_WIDTH {1'd0}};
      readData_int <= {LPCB_DATA_WIDTH {1'd0}};
      writeEn    <= 1'd0;
      readEn     <= 1'd0;
      frame_out  <= 1'd0;
      cad_out    <= 4'd0;
    end else begin
      writeEn    <= 1'd0;
      readEn     <= 1'd0;
      case(lpcb_state)
        RX_IDLE: begin
          lpcb_state <= 2'd0;
          lpcb_count <= 5'd0;
          lpcb_sel   <= 1'd0;
          addr       <= {LPCB_ADDRESS_WIDTH {1'd0}};
          writeData    <= {LPCB_DATA_WIDTH {1'd0}};
          readData_int <= {LPCB_DATA_WIDTH {1'd0}};
          writeEn      <= 1'd0;
          readEn       <= 1'd0;
          if (lpcb_abort) begin
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            lpcb_cmd   <= 4'd0;
            frame_out  <= 1'd0;
            cad_out    <= 4'd0;
          end else if (frame_int && (cad_int == `LPCB_READ_ACK_CMD)) begin
            lpcb_state <= PASS_THROUGH;
            lpcb_count <= 5'd8;
            lpcb_cmd   <= cad_int;
            frame_out  <= 1'd1;
            cad_out    <= cad_int;
          end else if (frame_int) begin
            lpcb_state <= GET_ADDR;
            lpcb_sel   <= 1'd1;
            case(cad_int)
              `LPCB_WRITE_8B_CMD  : lpcb_count <= 5'd1; // 2 addr - 1
              `LPCB_WRITE_16B_CMD : lpcb_count <= 5'd3; // 4 addr - 1
              `LPCB_WRITE_24B_CMD : lpcb_count <= 5'd5; // 6 addr - 1
              `LPCB_WRITE_32B_CMD : lpcb_count <= 5'd7; // 8 addr - 1
              `LPCB_READ_8B_CMD   : lpcb_count <= 5'd1; // 2 addr - 1         
              `LPCB_READ_16B_CMD  : lpcb_count <= 5'd3; // 4 addr - 1         
              `LPCB_READ_24B_CMD  : lpcb_count <= 5'd5; // 6 addr - 1         
              `LPCB_READ_32B_CMD  : lpcb_count <= 5'd7; // 8 addr - 1         
              default             : lpcb_count <= 5'd0; 
            endcase // case(cad_int)
            lpcb_cmd   <= cad_int;
            frame_out  <= 1'd1;
            cad_out    <= cad_int;
          end else begin
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= 1'd0;
            cad_out    <= 4'd0;
          end
        end

        PASS_THROUGH: begin
          frame_out  <= frame_int;
          cad_out    <= cad_int;
          if (frame_in) begin
            // command is being aborted by another command.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
          end else if (lpcb_count == 0) begin
            // we are done.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
          end else begin
            // still passing through read data from soneone upstream.
            lpcb_state <= PASS_THROUGH;
            lpcb_count <= lpcb_count - 5'd1;
          end
        end

        GET_ADDR: begin
          frame_out  <= frame_int;
          cad_out    <= cad_int;
          if (frame_in) begin
            // command is being aborted by another command.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
          end else begin
            if (lpcb_count == 0) begin
              lpcb_count <= 5'd7;
              case(lpcb_cmd)
                `LPCB_WRITE_8B_CMD  : lpcb_state <= GET_WRITE_DATA;
                `LPCB_WRITE_16B_CMD : lpcb_state <= GET_WRITE_DATA;
                `LPCB_WRITE_24B_CMD : lpcb_state <= GET_WRITE_DATA;
                `LPCB_WRITE_32B_CMD : lpcb_state <= GET_WRITE_DATA;
                `LPCB_READ_8B_CMD   : lpcb_state <= GET_READ_DATA;
                `LPCB_READ_16B_CMD  : lpcb_state <= GET_READ_DATA;
                `LPCB_READ_24B_CMD  : lpcb_state <= GET_READ_DATA;
                `LPCB_READ_32B_CMD  : lpcb_state <= GET_READ_DATA;
                default             : lpcb_state <= RX_IDLE;
              endcase // case(cad_int)10
            end else begin
              lpcb_state <= GET_ADDR;
              lpcb_count <= lpcb_count - 5'd1;
            end
            case(lpcb_count[2:0])\n"""

        if (self.addressWidth > 28):
            self.parent.verilogSetup += """              3'd7 : addr[31:28] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd7 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 24):
            self.parent.verilogSetup += """              3'd6 : addr[27:24] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd6 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 20):
            self.parent.verilogSetup += """              3'd5 : addr[23:20] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd5 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 16):
            self.parent.verilogSetup += """              3'd4 : addr[19:16] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd4 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 12):
            self.parent.verilogSetup += """              3'd3 : addr[15:12] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd3 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 8):
            self.parent.verilogSetup += """              3'd2 : addr[11: 8] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd2 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        if (self.addressWidth > 4):
            self.parent.verilogSetup += """              3'd1 : addr[ 7: 4] <= cad_int;\n"""
        else:
            self.parent.verilogSetup += """              3'd1 : lpcb_sel <= lpcb_sel & (cad_int == 4'd0);\n"""

        # address is always at least 4 bits.
        self.parent.verilogSetup += """              3'd0 : addr[ 3: 0] <= cad_int;
            endcase // case(count)
          end
        end

        GET_WRITE_DATA: begin
          frame_out  <= frame_int;
          cad_out    <= cad_int;
          if (frame_in) begin
            // command is being aborted by another command.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
          end else begin
            if (lpcb_count == 0) begin
              lpcb_state <= RX_IDLE;
              lpcb_count <= 5'd0;
              writeEn    <= lpcb_sel;
            end else begin
              lpcb_state <= GET_WRITE_DATA;
              lpcb_count <= lpcb_count - 5'd1;
            end
            case(lpcb_count[2:0])\n"""
        if (self.dataWidth >= 32):
            self.parent.verilogSetup += """              3'd7 : writeData[31:28] <= cad_int;\n"""
            self.parent.verilogSetup += """              3'd6 : writeData[27:24] <= cad_int;\n"""
        if (self.dataWidth >= 24):
            self.parent.verilogSetup += """              3'd5 : writeData[23:20] <= cad_int;\n"""
            self.parent.verilogSetup += """              3'd4 : writeData[19:16] <= cad_int;\n"""
        if (self.dataWidth >= 16):
            self.parent.verilogSetup += """              3'd3 : writeData[15:12] <= cad_int;\n"""
            self.parent.verilogSetup += """              3'd2 : writeData[11: 8] <= cad_int;\n"""
        # data is always >= 8.
            self.parent.verilogSetup += """              3'd1 : writeData[ 7: 4] <= cad_int;\n"""
            self.parent.verilogSetup += """              3'd0 : writeData[ 3: 0] <= cad_int;
            endcase // case(count)
          end
        end

        GET_READ_DATA: begin
          // read commands have precidence over all but abort and reset.
          if (lpcb_abort) begin
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= frame_int;
            cad_out    <= cad_int;
          end else if (~(lpcb_sel & localAddressValid)) begin
            // not our command, so go back to idle.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= frame_int;
            cad_out    <= cad_int;
          end else begin
            lpcb_state <= SEND_COMMAND;
            lpcb_count <= 5'd0;
            frame_out  <= 1'd0;
            cad_out    <= 4'd0;
            readEn     <= lpcb_sel;
          end
        end

        SEND_COMMAND: begin
          // read commands have precidence over all but abort and reset.
          if (lpcb_abort) begin
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= frame_int;
            cad_out    <= cad_int;
          end else if (lpcb_sel & localAddressValid) begin
            // we have a read function in our block, so ack it.
            lpcb_state <= SEND_READ_DATA;
            lpcb_count <= 5'd7;
            frame_out  <= 1'd1;
            cad_out    <= `LPCB_READ_ACK_CMD;
            readData_int <= readData;
          end else begin
            // the read was not for the module so finish up.
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= 1'd0;
            cad_out    <= 4'd0;
          end
        end

        SEND_READ_DATA: begin
          // read commands have precidence over all but abort and reset.
          if (lpcb_abort) begin
            lpcb_state <= RX_IDLE;
            lpcb_count <= 5'd0;
            frame_out  <= frame_int;
            cad_out    <= cad_int;
          end else begin
            if (lpcb_count == 5'd0) begin
              lpcb_state <= RX_IDLE;
              lpcb_count <= 5'd0;
              frame_out  <= 1'd0;
              cad_out    <= 4'd0;
            end else begin
              lpcb_state <= SEND_READ_DATA;
              lpcb_count <= lpcb_count - 5'd1;
              frame_out  <= 1'd0;
            end
            case(lpcb_count[2:0])\n"""
        if (self.dataWidth >= 32):
            self.parent.verilogSetup += """              3'd7 : cad_out <= readData_int[31:28];\n"""
            self.parent.verilogSetup += """              3'd6 : cad_out <= readData_int[27:24];\n"""
        else:
            self.parent.verilogSetup += """              3'd7 : cad_out <= 4'd0;\n"""
            self.parent.verilogSetup += """              3'd6 : cad_out <= 4'd0;\n"""

        if (self.dataWidth >= 32):
            self.parent.verilogSetup += """              3'd5 : cad_out <= readData_int[23:20];\n"""
            self.parent.verilogSetup += """              3'd4 : cad_out <= readData_int[19:16];\n"""
        else:
            self.parent.verilogSetup += """              3'd5 : cad_out <= 4'd0;\n"""
            self.parent.verilogSetup += """              3'd4 : cad_out <= 4'd0;\n"""

        if (self.dataWidth >= 32):
            self.parent.verilogSetup += """              3'd3 : cad_out <= readData_int[15:12];\n"""
            self.parent.verilogSetup += """              3'd2 : cad_out <= readData_int[11: 8];\n"""
        else:
            self.parent.verilogSetup += """              3'd3 : cad_out <= 4'd0;\n"""
            self.parent.verilogSetup += """              3'd2 : cad_out <= 4'd0;\n"""

        # data is always >= 8.
        self.parent.verilogSetup += """              3'd1 : cad_out <= readData_int[ 7: 4];\n"""
        self.parent.verilogSetup += """              3'd0 : cad_out <= readData_int[ 3: 0];
            endcase // case(count)
          end
        end

        default : begin
          lpcb_state <= RX_IDLE;
          lpcb_count <= 5'd0;
          lpcb_count <= 5'd0;
          frame_out  <= 1'd0;
          cad_out    <= 4'd0;
        end
      endcase // case(lpcb_state)
    end // else: !if(reset)
  end // if (clk_en)

  /*--------------------- end of lpcb slave setup ---------------------*/

"""
    # end of buildLpcbSlave()


# ubus slave.
#class Target_Bus_ubus(Target_Bus) :
#    """ This is the UBUS (micro bus) slave target bus class.  the ubus is a
#        simple request / ack based bus with 16 bit data and address ports.
#    """
#    def __init__ (self, hatchNode):
#        """ """
#
#    def elaborate (self):
#        """ Flesh out data structures for UBUS Slave as a prelude to generating anything."""
#        # get the prefix
#        prefix = self.property('prefix')
#
#        if self.property('bus') == 'ubus' :
#            self.parent.verilogSetup = "  //- - - - - - - - - - -  setup the ubus slave stuff. - - - - - - - - - - - -\n"
#
#            # clocks and reset.
#            self.clk        = "%sub_clk"%(prefix)
#            self.clkEn      = "%sub_clk_en"%(prefix)
#            self.gatedClk   = "%sgated_ub_clk"%(prefix)
#            self.gatedClkEn = "%sgated_ub_clk_en"%(prefix)
#            self.reset      = "%sub_reset"%(prefix)
#
#            self.ports.add("", self.clk)
#            self.ports.add("", self.clkEn)
#            self.ports.add("", self.gatedClk)
#            self.ports.add("", self.gatedClkEn)
#            self.ports.add("", self.reset)
#
#            # address bus width.
#            if self.function == 'mux' :
#                self.addrWidth = self.addressWidth
#
#            if self.function == 'slave' :
#                # calculate the number of bits to actualy use in the
#                # address decode. This assumes that the base address for
#                # every module is 0 and high order address decode is
#                # handled by another module up the hierachy. 
#                self.addrRange = self.hatchNode.get_address_range()
#                self.addrWidth = int(math.ceil(math.log(self.addrRange) / math.log(2.0))) - 2
#
#            self.addrWidthString = "[%d:1]"%(self.addrWidth)
#
#            self.addr       = "%sub_addr"%(prefix)
#            self.writeData  = "%sub_write_data"%(prefix)
#            self.writeEn    = "%sub_write"%(prefix)
#            self.readData   = "%sub_read_data"%(prefix)
#            self.readEn     = "%sub_read"%(prefix)
#
#            self.ports.add("", "%sub_ack"%(prefix))
#            self.ports.add(self.addrWidthString, self.addr)
#            self.ports.add("[15:0]",             self.writeData)
#            self.ports.add("",                   self.writeEn)
#            self.ports.add("[15:0]",            self.readData)
#            self.ports.add("",                   self.readEn)
#
#            if self.function == 'slave' :
#                
#                # pipeline address decode, so change the signals used.
#                self.writeEn    = "write_en" # a pulse.
#                self.readEn     = "read_en" # a level.
#                self.readData   = "read_data_int"
#
#                self.nets.add("", self.writeEn)
#                self.add_reg("", self.readEn)
#                self.add_reg("", "write_en_int")
#                self.add_reg("", "write_en_int_d")
#                self.nets.add("", "%sub_ack"%(prefix));
#                self.add_reg("[15:0]", self.readData)
#
#                self.parent.verilogSetup += """            
#  //
#  // read and write will be a combinatorial decode of the upper
#  // address bits so register them here to make the timing a 
#  // little easier
#  //
#  always @ (posedge %s) if (%s) begin
#    if (%s) begin
#"""%(self.gatedClk, self.gatedClkEn, self.reset)
#
#                self.parent.verilogSetup += """
#      read_en        <= 1'd0;
#      write_en_int   <= 1'd0;
#      write_en_int_d <= 1'd0;
#    end else begin
#      read_en        <= %sub_read;
#      write_en_int   <= %sub_write;
#      write_en_int_d <= write_en_int;
#    end
#  end
#"""%(prefix, prefix)
#
#                self.parent.verilogSetup += """  
#  assign write_en = write_en_int & ~write_en_int_d;
#  assign %sub_ack = read_en | write_en_int;
#  assign %sub_read_data = read_en ? %s : 16'd0;
#"""%(prefix, prefix, self.readData)
#
#                # tail the verilogSetup string.
#                self.parent.verilogSetup += """
#
#  //- - - - - - - - - - - end of ubus slave setup. - - - - - - - - - - -
#"""
